package com.scau402.system1.cipher;

import com.alibaba.fastjson2.JSON;
import com.scau402.common.exception.ServiceException;
import lombok.Data;
import org.apache.commons.lang3.RandomStringUtils;
import org.apache.commons.lang3.math.NumberUtils;

import java.util.HashMap;
import java.util.HashSet;
import java.util.Map;
import java.util.Set;
import java.util.function.Function;

public class CipherHandlerImpl2 implements CipherHandler {

    private static final Map<String, Function<Integer, String>> RANDOM_FUNCTION_MAP = new HashMap<>();

    static {
        RANDOM_FUNCTION_MAP.put("random", RandomStringUtils::randomAlphabetic);
        RANDOM_FUNCTION_MAP.put("upperCase", (length) -> RandomStringUtils.randomAlphabetic(length).toUpperCase());
        RANDOM_FUNCTION_MAP.put("lowerCase", (length) -> RandomStringUtils.randomAlphabetic(length).toLowerCase());
    }

    @Override
    public void checkIsValid(String configStr) {
        Config config = parse(configStr);
        if (config.getTotalLength() < 4) {
            throw new ServiceException("总长度应大于4");
        }
        if (null == RANDOM_FUNCTION_MAP.get(config.getMixType())) {
            throw new ServiceException("混淆码异常");
        }
        Set<String> set = new HashSet<>();
        for (int key = 0; key < 10; ++key) {
            String value = config.getNumMap().get(String.valueOf(key));
            if (!set.add(value)) {
                throw new ServiceException("数字" + key + "的替换" + value + "已重复(不区分大小写)");
            }
        }

        set = new HashSet<>();
        for (String value : config.getUnitMap().values()) {
            if (!set.add(value.toUpperCase()) || !set.add(value.toLowerCase())) {
                throw new ServiceException("价格替换字母" + value + "重复使用(不区分大小写)");
            }
        }
    }

    @Override
    public String convert(String configStr, String input) {
        Config config = parse(configStr);
        StringBuilder result = new StringBuilder(
                RANDOM_FUNCTION_MAP.get(config.getMixType()).apply(config.getTotalLength())
        );

        int num = (int) NumberUtils.toDouble(input);
        int unit = 1;
        while (1000 <= num) {
            num /= 10;
            unit *= 10;
        }

        String[] numString = {"0", "0", "0"};
        for (int i = numString.length - 1; 0 <= i && 0 < num; --i) {
            numString[i] = String.valueOf(num % 10);
            num /= 10;
        }

        result.setCharAt(
                config.getUnitPosition() - 1,
                config.getUnitMap().get(String.valueOf(unit)).charAt(0)
        );
        result.setCharAt(
                config.getNumPosition1() - 1,
                config.getNumMap().get(numString[0]).charAt(0)
        );
        result.setCharAt(
                config.getNumPosition2() - 1,
                config.getNumMap().get(numString[1]).charAt(0)
        );
        result.setCharAt(
                config.getNumPosition3() - 1,
                config.getNumMap().get(numString[2]).charAt(0)
        );

        return result.toString();
    }

    private Config parse(String configStr) {
        try {
            return JSON.parseObject(configStr, Config.class);
        } catch (Exception e) {
            throw new ServiceException("暗码配置异常");
        }
    }


    @Data
    private static class Config {
        private int totalLength;
        private String mixType;

        private int unitPosition;
        private int numPosition1;
        private int numPosition2;
        private int numPosition3;

        private Map<String, String> numMap;
        private Map<String, String> unitMap;

    }
}
